'''  分段线性函数在[0,5]上函数如下
         ╭  x         (0≤x ≤2)
Max f(x)=┃
         ╰ x/3 + 4/3  (0≤x ≤2)

setPWLObj( var,x, y )  目标函数(分段线性目标)
var指定变量的目标函数是分段线性
x定义分段线性目标函数的点的横坐标值(非减序列)
y定义分段线性目标函数的点的纵坐标值
对一些非线性模型，可以使用这一功能去线性逼近。
'''
from gurobipy import *
import gurobipy as gp
m= gp.Model("分段线性")

x = m.addVar(obj=1, vtype = GRB.CONTINUOUS,name="x")  #obj=1 是系数
y = m.addVar(obj=1, vtype = GRB.CONTINUOUS,name="y")
z = m.addVar(obj=1, vtype = GRB.CONTINUOUS,name="z")

m.setPWLObj(x,[0,2,5],[0,2,3])  #分段函数取端点处的坐标  (0,0) (2,2) (5,3)
m.write( "example_PWLObj.lp")



'''分段目标案例(逼近非线性)'''
#     min f(x) = (x-1)² + 2, x ∈[0,10]
# 上面模型可以用Gurobi直接求解,最优解为f(1) = 2。
# 本案例要求使用线性逼近的方法求解模型。

from gurobipy import *
import gurobipy as gp
try:
    #分制的密度
    npts = 10000   #切割成9999份，密度放大一点 直线分割的越来越小就越接近曲线，使结果越来越接近
    m = gp.Model("抛物线的最小值求解")
    #添加变量
    x = m.addVar(ub=10,vtype=GRB.CONTINUOUS,name='x ')
    #定义分割点
    px = []
    f  = []
    for i in range(npts):
        px.append(10* i / (npts - 1))
        f.append((px[i]*px[i])-2*px[i] +3)    #  x²-2x+3
    m.setPWLObj(x, px,f)
    #启动求解
    m.optimize()
    #获得求解结果
    print( '0bj: %g' % m.ObjVal)
    for v in m.getVars():
        print( '%s %f' % (v.VarName,v.X))
    m.write("PML.lp")
except GurobiError:
    print( 'Error reported ')
